﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using MealBooking.Core.Models.Meals;
using System.IO;
using System.Xml.Linq;

namespace MealBooking.Core.Common
{
    public static class ModelSerializer
    {
        #region property
        private static XmlSerializerNamespaces xmlSerializerNamespace = new XmlSerializerNamespaces();
        private static bool hasAdded = false;
        private static Dictionary<string, XmlSerializer> serializers = new Dictionary<string, XmlSerializer>();
        private static object _locker = new object();
        #endregion

        #region private method
        private static XmlSerializer GetXmlSerializer(Type T)
        {
            string typeName = T.FullName;
            if (serializers.ContainsKey(typeName))
            {
                return serializers[typeName];
            }
            lock (_locker)
            {
                if (!serializers.ContainsKey(typeName))
                {
                    XmlSerializer serializer = new XmlSerializer(T);
                    serializers.Add(typeName, serializer);
                }
            }
            return serializers[typeName];
        }
        #endregion

        #region Serialize and Deserialize
        public static T Clone<T>(T data)
        {
            if (!hasAdded)
            {
                xmlSerializerNamespace.Add("", "");
                hasAdded = true;
            }
            T result = default(T);
            if (data != null)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    var xmlSerialzer = ModelSerializer.GetXmlSerializer(typeof(T));
                    xmlSerialzer.Serialize(stream, data, xmlSerializerNamespace);
                    stream.Seek(0, SeekOrigin.Begin);
                    stream.Flush();
                    XElement frag = XElement.Load(stream);
                    result = (T)xmlSerialzer.Deserialize(frag.CreateReader());
                }
            }
            return result;
        }
        public static XElement Serialize<T>(T data)
        {
            if (!hasAdded)
            {
                xmlSerializerNamespace.Add("", "");
                hasAdded = true;
            }
            XElement result = null;
            if (data != null)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    var xmlSerialzer = ModelSerializer.GetXmlSerializer(typeof(T));
                    xmlSerialzer.Serialize(stream, data, xmlSerializerNamespace);
                    stream.Seek(0, SeekOrigin.Begin);
                    stream.Flush();
                    result = XElement.Load(stream);
                }
            }
            return result;
        }
        public static List<XElement> Serialize<T>(List<T> data)
        {
            if (!hasAdded)
            {
                xmlSerializerNamespace.Add("", "");
                hasAdded = true;
            }
            if (data == null)
            {
                return null;
            }
            List<XElement> result = new List<XElement>();
            using (MemoryStream stream = new MemoryStream())
            {
                var xmlSerialzer = ModelSerializer.GetXmlSerializer(typeof(T));
                foreach (var tempData in data)
                {
                    xmlSerialzer.Serialize(stream, tempData, xmlSerializerNamespace);
                    stream.Seek(0, SeekOrigin.Begin);
                    stream.Flush();
                    XElement frag = XElement.Load(stream);
                    if (frag != null)
                    {
                        result.Add(frag);
                    }
                    stream.SetLength(0);
                }
            }
            return result;
        }
        public static T Deserialize<T>(XElement data)
        {
            T result = default(T);
            if (data != null)
            {
                var xmlSerialzer = ModelSerializer.GetXmlSerializer(typeof(T));
                result = (T)xmlSerialzer.Deserialize(data.CreateReader());
            }
            return result;
        }
        public static List<T> Deserialize<T>(IEnumerable<XElement> data)
        {
            if (data == null || data.Count() == 0)
            {
                return null;
            }
            List<T> result = new List<T>();
            var xmlSerialzer = ModelSerializer.GetXmlSerializer(typeof(T));
            foreach (var tempData in data)
            {
                if (tempData != null)
                {
                    T temp = (T)xmlSerialzer.Deserialize(tempData.CreateReader());
                    if (temp != null)
                    {
                        result.Add(temp);
                    }
                }
            }
            return result;
        }
        #endregion
    }
}
